﻿// SIFTDetection.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <opencv2/xfeatures2d/nonfree.hpp>


using namespace cv;
using namespace std;

int main()
{
	Mat church = imread("E:\\VC_project\\figure\\church.jpg");
	Mat chess = imread("E:\\VC_project\\figure\\chess.jpg");
	Mat lena = imread("E:\\VC_project\\figure\\lena.jpg");

	double t = getTickCount();//当前滴答数
	if (chess.empty()||chess.empty()||lena.empty())
	{
		cout << "图片读取失败！" << endl;
		return -1;
	}
	
	//对图像进行旋转变化
	Mat lena90;
	transpose(lena, lena90);
	flip(lena90, lena90, 1);

	//对图像进行灰度处理
	Mat graychess, graychurch, grayLena,grayLena90;
	cvtColor(chess, graychess, COLOR_BGR2GRAY);
	cvtColor(church, graychurch, COLOR_BGR2GRAY);
	cvtColor(lena, grayLena, COLOR_BGR2GRAY);
	cvtColor(lena90, grayLena90, COLOR_BGR2GRAY);
	
	//创建sift算子
	Ptr<Feature2D>sift = xfeatures2d::SIFT::create();
	vector<KeyPoint>keypoints1, keypoints2, keypoints3, keypoints4;//存放特征点
	Mat descriptors1, descriptors2;//用来存放特征点的描述向量

	//使用SIFT算子检测chess和church特征点
	sift->detect(graychurch, keypoints1, Mat());
	sift->detect(graychess, keypoints2, Mat());

	//在原图中画出特征点
	drawKeypoints(church, keypoints1, church, Scalar(0, 0, 255));
	drawKeypoints(chess, keypoints2, chess, Scalar(0, 0, 255));

	t = ((double)getTickCount() - t) / getTickFrequency();
	cout << "算法用时：" << t << "秒" << endl;// t=0.343s

	//使用SIFT算子检测lena的特征点和描述子向量
	sift->detectAndCompute(grayLena, Mat(), keypoints3, descriptors1);
	sift->detectAndCompute(grayLena90, Mat(), keypoints4, descriptors2);

	//实例化一个FLANN匹配器
	FlannBasedMatcher matcher;

	//DMatch是用来描述匹配好的一对特征点的类，包含这两个点之间的匹配信息
	//比如左图有个特征m，它和右图的特征点n最匹配，这个DMatch就记录它俩最匹配，并且还记录m和n的
	//特征向量的距离和其他信息，这个距离在后面用来做筛选
	vector<DMatch> matches;

	//匹配，数据来源是特征向量，结果存放在DMatch类型里面  
	matcher.match(descriptors1, descriptors2, matches);
	
	//求最小最大距离
	double minDistance = 1000;//反向逼近
	double maxDistance = 0;
	for (int i = 0; i < descriptors1.rows; i++)
	{
		double distance = matches[i].distance;
		if (distance > maxDistance)
		{
			maxDistance = distance;
		}
		if (distance < minDistance)
		{
			minDistance = distance;
		}	
	}
	cout << "最小距离：" << minDistance << endl;
	cout << "最大距离：" << maxDistance << endl;
	//筛选较好的匹配点
	vector<DMatch> goodMatches;
	for (int i = 0; i < descriptors1.rows; i++)
	{
		double distance = matches[i].distance;
		if (distance < max(minDistance*2, 0.001))
			goodMatches.push_back(matches[i]);//距离小于范围的压入新的DMatch
	}
	//画出匹配图
	Mat img_matches;
	drawMatches(lena, keypoints3, lena90, keypoints4, goodMatches, img_matches, Scalar::all(-1), Scalar::all(-1), vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);


	imshow("SIFT_chess角点检测", chess);
	imshow("SIFT_church角点检测", church);
	imshow("SIFT_lena角点匹配", img_matches);
	waitKey();

}


